package com.yiba.vpn.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import com.yiba.vpn.domain.SharingInvitationsRecord;
import com.yiba.vpn.dto.RefreshTokenDto;
import com.yiba.vpn.dto.VcodeDto;
import com.yiba.vpn.dto.WfInfoDto;
import com.yiba.vpn.repository.SharingInvitationsRepository;
import freemarker.template.TemplateException;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.google.code.kaptcha.Producer;
import com.yiba.vpn.authorization.manager.TokenManager;
import com.yiba.vpn.authorization.model.OauthRefreshModel;
import com.yiba.vpn.authorization.model.OauthUserModel;
import com.yiba.vpn.authorization.model.TokenModel;
import com.yiba.vpn.authorization.model.UserModel;
import com.yiba.vpn.config.Config;
import com.yiba.vpn.config.Constants;
import com.yiba.vpn.config.ResultStatus;
import com.yiba.vpn.domain.User;
import com.yiba.vpn.dto.UserDto;
import com.yiba.vpn.model.ResultModel;
import com.yiba.vpn.repository.UserRepository;
import com.yiba.vpn.util.Iputil;
import com.yiba.vpn.util.StringUtils;
import com.yiba.vpn.util.TokenUtil;
import com.yiba.vpn.util.UUIDUtil;
import com.yiba.vpn.util.location.IPLLDecodeUtils;
import com.yiba.www.pojo.IPLLData;

@Service
public class UserService {

    private static Logger logger = Logger.getLogger(UserService.class);


    @Autowired
    private TokenManager tokenManager;

  /*  @Autowired
    private HttpServletRequest request;*/

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private SharingInvitationsRepository sharingInvitationsRepository;

    @Autowired
    private Config config;

    @Autowired
    private MailService mailService;

    @Value("${gecco.mail.action.ftl}")
    private String FREEMARK_ID_ACTION;

    @Value("${gecco.mail.fdpwd.ftl}")
    private String FREEMARK_ID_FDPWD;

    @Value("${gecco.mail.rsetpwd.ftl}")
    private String FREEMARK_ID_RSETPWD;

    @Value("${gecco.server.host}")
    private String SEVER_HOST;

    @Autowired
    private InviteService inviteService;

    @Autowired
    private WalletService walletService;

    @Autowired
    private EmailProcessService emailProcessService;


    @Transactional
    public UserModel login(UserDto userDto) {
        int loginChannel = userDto.getLoginChannel();
        String accountUUid = UUID.randomUUID().toString().replace("-", "");
        User user = null;
        UserModel userModel = null;
        Integer newTestService = 0;
        try {
            if (loginChannel == 0) {
                //游客
                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    //新用户
                    String account = "yk-" + accountUUid;
                    user = covertUser(userDto, account);
                    //新用户生成套餐
                    //  newTestService = addSetMealNew(user);

                }

            } else if (loginChannel == 1) {
                //微信登录

                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    String account = "wx-" + accountUUid;
                    user = covertUser(userDto, account);
                    //新用户生成套餐
                    //newTestService = addSetMeal(user);
                }

            } else if (loginChannel == 2) {
                //facebook
                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    String account = "fb-" + accountUUid;
                    user = covertUser(userDto, account);
                    //新用户生成套餐
                    //newTestService = addSetMeal(user);
                }
            } else if (loginChannel == 3) {
                //如果手机端 直接用邮箱登录
                //email 邮箱登录 PlatformId  就是邮箱号
                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    //表示不存在 进行注册
                    String account = "" + userDto.getPlatformId();
                    user = covertUser(userDto, account);
                    //邮箱注册的用户 不生成套餐
                    // newTestService = addSetMeal(user);
                }

                if (user != null && user.getIsactivity() != 1) {
                    //表示该用户没有激活 不允许登录
                    userModel.setToken("-1302");
                    return userModel;
                }
                if (user != null && user.getPwd().equals(userDto.getPwd())) {
                    //表示该用户密码不正确 不允许登录
                    userModel.setToken("-1404");
                    return userModel;
                }
            }

            if (null != user) {
                //生成一个token，保存用户登录状态
                userModel = createToken(user, newTestService);
            }
        } catch (Exception e) {
            logger.error("生成用户系统异常：{}" + e);
            return userModel;
        }
        return userModel;
    }


    /**
     * 老版创建Token
     */
    public UserModel createToken(User user, Integer newTestService) {
        //使用uuid作为源token
        String account = user.getAccount();
        String vpnId = user.getVpnId();
        String token = TokenUtil.getToken(user, config.getTokenKey());
        UserModel model = new UserModel(account, vpnId, token, newTestService);
        //存储到redis并设置过期时间
        tokenManager.addValue(account, token, Constants.TOKEN_EXPIRES_SECONDS, TimeUnit.SECONDS);
        return model;
    }


    private User covertUser(UserDto userDto, String account) throws UnsupportedEncodingException {
        User user = new User();
        user.setAccount(account);
        String platformId = userDto.getPlatformId();
        user.setPlatformId(platformId);
        user.setUuid(userDto.getUuid());
        user.setVpnId(UUIDUtil.generateNumber());
        user.setLoginChannel(userDto.getLoginChannel());
        user.setSex(userDto.getSex());
        if (!StringUtils.isNullOrEmpty(userDto.getUsername())) {
            user.setUsername(URLEncoder.encode(userDto.getUsername(), "utf-8"));
        }
        // 邮箱需要激活
        if (account.equals(userDto.getPlatformId())) {
            user.setIsactivity(1);
            user.setPwd(userDto.getPwd());
        } else {
            user.setIsactivity(1);
        }
        user.setIcon(userDto.getIcon());
        user.setBirthday(userDto.getBirthday());
        user.setEmail(userDto.getBirthday());
        user.setLink(userDto.getLink());
        user.setTimezone(userDto.getTimezone());
        user.setOs(userDto.getOs());
        user.setOsVer(userDto.getOsVer());
        user.setAppVer(userDto.getAppVer());
        user.setWfee(0);
        return this.userRepository.save(user);
    }


    /**
     * outah登录
     *
     * @param userDto
     * @return
     */
    public OauthUserModel oauthLogin(UserDto userDto) {
        int loginChannel = userDto.getLoginChannel();
        String accountUUid = UUID.randomUUID().toString().replace("-", "");
        User user = null;
        OauthUserModel oauthUserModel = null;
        Integer newTestService = 0;
        try {
            if (loginChannel == 0) {
                //游客
                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    //新用户
                    String account = "yk-" + accountUUid;
                    user = covertUser(userDto, account);
                    //新用户生成套餐
                    //newTestService = addSetMealNew(user);
                }

            } else if (loginChannel == 1) {
                //微信登录

                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    String account = "wx-" + accountUUid;
                    user = covertUser(userDto, account);
                    //新用户生成套餐
                    //  newTestService = addSetMeal(user);
                }

            } else if (loginChannel == 2) {
                //facebook
                user = userRepository.findByPlatformId(userDto.getPlatformId());
                if (null == user) {
                    String account = "fb-" + accountUUid;
                    user = covertUser(userDto, account);
                    //新用户生成套餐
                    // newTestService = addSetMeal(user);
                }
            }

            if (null != user) {
                //生成一个token，保存用户登录状态
                oauthUserModel = outhCreateToken(user, newTestService);
            }
        } catch (Exception e) {
            logger.error("生成用户系统异常：{}" + e);
            return oauthUserModel;
        }
        return oauthUserModel;
    }

    /**
     * 生成token
     *
     * @param user
     * @param newTestService
     * @return
     */
    private OauthUserModel outhCreateToken(User user, Integer newTestService) {
//使用uuid作为源token
        String account = user.getAccount();
        String vpnId = user.getVpnId();
        OauthUserModel oauthUserModel = null;
        //存储到redis并设置过期时间
        String refreshTokenKey = Constants.REFRESH_REDIS_VPN_PREFIX + user.getId();
        String existToken = tokenManager.getValue(account);
        String existRefreshToken = tokenManager.getValue(refreshTokenKey);
        if (!StringUtils.isEmpty(existToken) && !StringUtils.isEmpty(existRefreshToken)) {
            //token不为空说明没有过期
            oauthUserModel = new OauthUserModel(existToken, existRefreshToken, tokenManager.getExpireTimeType(account), account, vpnId, newTestService);
        } else {
            //token为空
            String token = TokenUtil.getToken(user, config.getTokenKey());
            String reFreshToken = TokenUtil.getEncryptRefreshToken(account, config.getTokenKey());
            tokenManager.addValue(account, token, Constants.TOKEN_EXPIRES_SECONDS, TimeUnit.SECONDS);
            tokenManager.addValue(refreshTokenKey, reFreshToken, Constants.REFRESH_TOKEN_EXPIRES_DAYS, TimeUnit.DAYS);
            oauthUserModel = new OauthUserModel(token, reFreshToken, Constants.TOKEN_EXPIRES_SECONDS, account, vpnId, newTestService);
        }
        return oauthUserModel;
    }

    /**
     * 刷新token
     *
     * @param refreshToken
     * @return
     */
    public synchronized ResponseEntity<ResultModel> oauthRefreshToken(String refreshToken) {
        String decryptRefreshToken = TokenUtil.getDecryptRefreshToken(refreshToken, config.getTokenKey());

        if (StringUtils.isEmpty(decryptRefreshToken)) {
            //刷新的token不对，请检查
            return new ResponseEntity<>(ResultModel.error(ResultStatus.NO_REFRESH_TOKEN), HttpStatus.OK);
        }
        User user = validateRefreshToken(decryptRefreshToken, refreshToken);
        if (null == user) {
            //token是伪造的。非法的
            return new ResponseEntity<>(ResultModel.error(ResultStatus.NO_REFRESH_TOKEN), HttpStatus.OK);
        }

        OauthRefreshModel oauthRefreshModel = null;
        //token 是不是有效期内，如果有效期不刷新
        if (tokenManager.ttlKey(user.getAccount()).intValue() != -2) {
            //没有过期
            String existToken = tokenManager.getValue(user.getAccount());
            String existRefreshToken = tokenManager.getValue(Constants.REFRESH_REDIS_VPN_PREFIX + user.getId());
            long expireTime = tokenManager.getExpireTimeType(user.getAccount());
            oauthRefreshModel = new OauthRefreshModel(existToken, existRefreshToken, expireTime);
        } else {
            String account = user.getAccount();
            String refreshTokey = Constants.REFRESH_REDIS_VPN_PREFIX + user.getId();
            //token过期了
            String token = TokenUtil.getToken(user, config.getTokenKey());
            String reFreshToken = TokenUtil.getEncryptRefreshToken(account, config.getTokenKey());
            tokenManager.addValue(account, token, Constants.TOKEN_EXPIRES_SECONDS, TimeUnit.SECONDS);
            tokenManager.addValue(refreshTokey, reFreshToken, Constants.REFRESH_TOKEN_EXPIRES_DAYS, TimeUnit.DAYS);
            oauthRefreshModel = new OauthRefreshModel(token, reFreshToken, Constants.TOKEN_EXPIRES_SECONDS);
        }
        return new ResponseEntity<>(ResultModel.ok(oauthRefreshModel), HttpStatus.OK);
    }

    /**
     * 校验token
     *
     * @param decryptRefreshToken
     * @return
     */
    private User validateRefreshToken(String decryptRefreshToken, String refreshTokenDto) {
        User user = null;
        String[] refreshTokens = decryptRefreshToken.split("\\|");
        if (refreshTokens.length != 3) {
            return user;
        }
        String account = refreshTokens[0];
        //校验数据库用户在不在
        User existUser = this.userRepository.findByAccount(account);
        if (null == existUser) {
            //用户不存在
            return user;
        }
        String refreshTokenKey = Constants.REFRESH_REDIS_VPN_PREFIX + existUser.getId();
        String redisRefreshToken = this.tokenManager.getValue(refreshTokenKey);
        if (!StringUtils.isEmpty(redisRefreshToken) && redisRefreshToken.equals(refreshTokenDto)) {
            //查询出来的token和
            user = existUser;
        }
        return user;
    }

    /**
     * Web端登录
     *
     * @param userDto
     * @return
     */
    public OauthUserModel loginweb(UserDto userDto, String invitationcode) {
        User user = null;
        OauthUserModel oauthUserModel = null;
        Integer newTestService = 0;
        user = userRepository.findByPlatformId(userDto.getPlatformId());
        if (null == user) {
            //表示不存在 进行注册
            String account = "" + userDto.getPlatformId();
            try {
                user = covertUser(userDto, account);
                // 然后再分享wfee 币
                /*if (!StringUtils.isNullOrEmpty(invitationcode)) {
                    User sendInvitationUser = userRepository.findByVpnId(invitationcode);
                    if (sendInvitationUser != null) {
                        //addWfeeValue(user.getAccount(), sendInvitationUser.getAccount());
                    } else {
                        //恶意利用邀请链接发送
                        logger.error("恶意利用邀请链接发送 !" + invitationcode);
                    }

                }*/
            } catch (Exception e) {
            }
        }
        if (null != user) {
            //生成一个token，保存用户登录状态
            try {
                oauthUserModel = outhCreateToken(user, newTestService);
            } catch (Exception e) {
                logger.error("生成用户系统异常：{}" + e);
                return oauthUserModel;
            }
        }
        return oauthUserModel;

    }

    //增送WifiB 并添加记录
    private void addWfeeValue(String account, String invitationcode) {
        //先添加记录 如果没加过就 加上去
        SharingInvitationsRecord si = new SharingInvitationsRecord();
        si.setAccount(invitationcode);
        si.setInvitation(account);
        si.setCreate_at(new Date());
        sharingInvitationsRepository.save(si);

        userRepository.updateWfeeByAccount(invitationcode, 0, 550);

    }

    public Map<String, String> sendemailbyemailtype(String email, Integer emailtype) throws IOException, TemplateException {

        User user = userRepository.findByPlatformId(email);

        Map<String, Object> model = new HashMap<>();
        model.put("ecode", 0);
        model.put("account", email);
        return mailService.sendHtmlMailUsingFreeMarker(model, email, FREEMARK_ID_FDPWD, emailtype);
    }


    public ResponseEntity sendVcodeEmail(VcodeDto vcodeDto) {
        //发送邮件
        Map<String, Object> model = new HashMap<>();
        model.put("ecode", vcodeDto.getCode());
        model.put("account", vcodeDto.getEmail());
        try {
            mailService.sendHtmlMailUsingFreeMarker(model, vcodeDto.getEmail(), FREEMARK_ID_FDPWD, null);
            //10分钟 Code 时间
            tokenManager.addValue(vcodeDto.getEmail() + "_" + vcodeDto.getCode(), vcodeDto.getCode(), Constants.REGISTER_EXPIRES_SECONDS, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<>(ResultModel.error(ResultStatus.INTERNAL_SERVER_ERROR), HttpStatus.OK);
        }
        return new ResponseEntity<>(ResultModel.ok(), HttpStatus.OK);
    }


    /**
     * 老的接口刷新Token(有漏洞)
     *
     * @return
     */
    public TokenModel refreshToken(RefreshTokenDto refreshToken) {
        String account = refreshToken.getAccount();
        String uuid = refreshToken.getUuid();
        String token = null;
        String existToken = tokenManager.getValue(account);
        if (StringUtils.isEmpty(existToken)) {
            //说明token为空
            token = installToken(account, uuid);
        } else {
            //说明token不为空
            tokenManager.deleteKey(account);
            token = installToken(account, uuid);
        }

        TokenModel tokenModel = new TokenModel(account, token);
        //存储到redis并设置过期时间
        tokenManager.addValue(account, token, Constants.TOKEN_EXPIRES_SECONDS, TimeUnit.SECONDS);
        return tokenModel;
    }

    private String installToken(String account, String uuid) {
        User user = new User();
        user.setAccount(account);
        user.setUuid(uuid);
        return TokenUtil.getToken(user, config.getTokenKey());
    }

    public WfInfoDto queryWfinfo(String email) {
        WfInfoDto wf = null;
        User user = userRepository.findByAccount(email);
        if (user == null) {
            return wf;
        }
        Integer invitingAwards = 0;
        //邀请人个数
        Integer invitingPersonNum = sharingInvitationsRepository.countInvitatingNumByAccount(email);

        if (invitingPersonNum > 10) {
            invitingAwards = 500;
            invitingPersonNum = 10;
        } else {
            invitingAwards = invitingPersonNum * 50;
            if (user.getWfee() != 0 && invitingAwards != user.getWfee() - 50) {
            	invitingPersonNum =  (user.getWfee() - 50 ) / 50;
            }
        }
        String invitingUrl = inviteService.createUrl(email);
        wf = new WfInfoDto(invitingUrl, user.getWfee(), user.getWfee() - 50, invitingPersonNum);
        //查询是否有钱包并返回
        wf.setWallet(walletService.getWallet(email));
        return wf;
    }
}
